package requests

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"strconv"
	"time"
)

func Post(url string, args ...interface{}) *requests {
	Rquest := requestInit{url: url, TimeOut: time.Second * 10}
	var res *http.Request

	// 优先判断请求体传参形式并检查其合法性
	for _, value := range args {
		switch value := value.(type) {
		case bool:
			Rquest.IsJson = value
		case Param:
			Rquest.Param = value
		case Header:
			Rquest.Header = value
		case Cookie:
			Rquest.Cookie = value
		case time.Duration:
			Rquest.TimeOut = value
		case Body:
			// 如果传入了Body则直接保存
			Rquest.Body = value
		case Proxy:
			if err := setProxy(string(value), &Rquest); err != nil {
				fmt.Printf("%v", err)
				return nil
			}
		default:
			println("Passing in illegal format parameters")
			return nil
		}
	}
	// 判断param是否多余
	if (Rquest.Param != nil || Rquest.IsJson == true) && Rquest.Body != nil {
		println("Extra parameters are passed in!")
		return nil
	}
	// 添加传入的传参
	if Rquest.Param != nil {
		if Rquest.IsJson {
			var err error
			Rquest.Body, err = json.Marshal(Rquest.Param)
			if err != nil {
				fmt.Printf("json encoding error. err:%v", err)
				return nil
			}
		} else {
			var bodyStr string = ""
			for key, value1 := range Rquest.Param {
				if key != "" {
					switch value1 := value1.(type) {
					case string:
						Rquest.IsForm = true
						bodyStr = bodyStr + key + "=" + value1 + "&"
					case int:
						bodyStr = bodyStr + key + "=" + strconv.Itoa(value1) + "&"
					default:
						fmt.Println("Incoming parameters are out of format")
						return nil
					}
				} else {
					fmt.Println("The key cannot be empty!")
					return nil
				}
			}
			Rquest.Body = []byte(bodyStr)
			Rquest.Body = Rquest.Body[:len(Rquest.Body)-1]
		}
	}
	res, err := http.NewRequest("POST", Rquest.url, bytes.NewBuffer(Rquest.Body))
	if err != nil {
		fmt.Printf("Request requests creation failed. err:%v", err)
		return nil
	}
	if Rquest.IsJson {
		res.Header.Set("Content-Type", "application/json")
	} else if Rquest.IsForm {
		res.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	// 添加请求头
	for k, v := range Rquest.Header {
		res.Header.Add(k, v)
	}
	// 添加cookie
	for k, v := range Rquest.Cookie {
		sessionCookie := &http.Cookie{
			Name:  k,
			Value: v,
		}
		res.AddCookie(sessionCookie)
	}
	// 发送请求
	client := &http.Client{
		Transport: func() http.RoundTripper {
			if Rquest.Proxy == nil {
				return nil
			} else {
				return Rquest.Proxy
			}
		}(),
		Timeout: Rquest.TimeOut,
	}
	// 获取HTTP请求的包
	dump, err := httputil.DumpRequestOut(res, true)
	if err != nil {
		fmt.Printf("Failed to obtain HTTP packets. err:%v", err)
		return nil
	}
	// 发送请求
	respond, err := client.Do(res)
	if err != nil {
		fmt.Printf("connection failure!!! err:%v", err)
		return nil
	}
	defer respond.Body.Close()
	// 定义返回的结构体
	var resStruct requests
	// 定义响应包的缓冲区
	var buf bytes.Buffer
	_, err = io.Copy(&buf, respond.Body)
	if err != nil {
		fmt.Printf("Fail to read body. err:%v", err)
		return nil
	}
	// 在 buf 中可以获取到响应体数据
	resStruct.Text = buf.String()
	resStruct.HttpText = string(dump)
	resStruct.Status = respond.Status
	return &resStruct
}
